package com.zh.harmony.butterknife;

import com.zh.harmony.butterknife.annotations.Bind;
import com.zh.harmony.butterknife.annotations.OnClick;
import com.zh.harmony.butterknife.annotations.OnLongClick;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.AbilitySlice;
import ohos.agp.components.Component;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * ButterKnife入口类
 */
public class ButterKnife {
    /**
     * Ability使用
     */
    public static void inject(Ability ability) {
        Finder finder = createAbilityFinder(ability);
        findComponentById(finder);
        setOnClickListener(finder);
        setOnLongListener(finder);
    }

    /**
     * AbilitySlice使用
     */
    public static void inject(AbilitySlice slice) {
        Finder finder = createAbilitySliceFinder(slice);
        findComponentById(finder);
        setOnClickListener(finder);
        setOnLongListener(finder);
    }

    private static Finder createAbilityFinder(Ability ability) {
        return new Finder() {
            @Override
            public Object getTarget() {
                return ability;
            }

            @Override
            public Class<?> getTargetClass() {
                return ability.getClass();
            }

            @Override
            public Component findComponentById(int id) {
                return ability.findComponentById(id);
            }
        };
    }

    private static Finder createAbilitySliceFinder(AbilitySlice slice) {
        return new Finder() {
            @Override
            public Object getTarget() {
                return slice;
            }

            @Override
            public Class<?> getTargetClass() {
                return slice.getClass();
            }

            @Override
            public Component findComponentById(int id) {
                return slice.findComponentById(id);
            }
        };
    }

    private interface Finder {
        /**
         * 获取需要被注入的对象
         */
        Object getTarget();

        /**
         * 获取需被要注入的对象的Class
         */
        Class<?> getTargetClass();

        /**
         * 根据id查找组件
         */
        Component findComponentById(int id);
    }

    /**
     * 反射查找AbilitySlice上的成员变量的注解，注入Component组件
     */
    private static void findComponentById(Finder finder) {
        Object target = finder.getTarget();
        Class<?> targetClass = finder.getTargetClass();
        //获取Ability上的所有成员变量
        Field[] declaredFields = targetClass.getDeclaredFields();
        //遍历成员变量
        for (Field field : declaredFields) {
            //获取成员变量上的注解
            Bind annotation = field.getAnnotation(Bind.class);
            if (annotation != null) {
                //获取注解上的id值
                int componentId = annotation.value();
                //根据id，从AbilitySlice中查找控件
                Component component = finder.findComponentById(componentId);
                try {
                    //反射注入控件实例
                    field.setAccessible(true);
                    field.set(target, component);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 设置点击事件
     */
    private static void setOnClickListener(Finder finder) {
        Object target = finder.getTarget();
        Class<?> targetClass = finder.getTargetClass();
        Method[] declaredMethods = targetClass.getDeclaredMethods();
        for (Method method : declaredMethods) {
            OnClick annotation = method.getAnnotation(OnClick.class);
            if (annotation != null) {
                int[] componentIds = annotation.values();
                for (int componentId : componentIds) {
                    Component component = finder.findComponentById(componentId);
                    if (component != null) {
                        component.setClickedListener(new Component.ClickedListener() {
                            @Override
                            public void onClick(Component component) {
                                try {
                                    method.setAccessible(true);
                                    try {
                                        //先调用无参方法
                                        method.invoke(target);
                                    } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                                        e.printStackTrace();
                                        //失败，再调用一个参数的方法
                                        method.invoke(target, component);
                                    }
                                } catch (IllegalAccessException | InvocationTargetException e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                    }
                }
            }
        }
    }

    /**
     * 设置长按事件
     */
    private static void setOnLongListener(Finder finder) {
        Object target = finder.getTarget();
        Class<?> targetClass = finder.getTargetClass();
        Method[] declaredMethods = targetClass.getDeclaredMethods();
        for (Method method : declaredMethods) {
            OnLongClick annotation = method.getAnnotation(OnLongClick.class);
            if (annotation != null) {
                int[] componentIds = annotation.values();
                for (int componentId : componentIds) {
                    Component component = finder.findComponentById(componentId);
                    if (component != null) {
                        component.setLongClickedListener(new Component.LongClickedListener() {
                            @Override
                            public void onLongClicked(Component component) {
                                try {
                                    method.setAccessible(true);
                                    try {
                                        //先调用无参方法
                                        method.invoke(target);
                                    } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                                        e.printStackTrace();
                                        //失败，再调用一个参数的方法
                                        method.invoke(target, component);
                                    }
                                } catch (IllegalAccessException | InvocationTargetException e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                    }
                }
            }
        }
    }
}